在上篇說明了 Angular 幾個生命週期鉤子方法 (Lifecycle hook methods),而這篇將繼續說明 AfterContentInit
與 AfterContentChecked
兩個鉤子方法 (hook methods);並新增 PageContainer 與 PageTitle 兩個元件實作,讓待辦事項應用程式的每個頁面有一樣的版型。
由於預計要實作的元件功能較不同於待辦事項,因此利用 Angular CLI 建立 UiModule,並在此建立 PageContainer 與 PageTitle 兩個元件,並在 page-container.component.css 中加入頁面標題的樣式。
div.page-title {
border-bottom: solid 1px rgba(0, 0, 0, 0.12);
padding-top: 1em;
padding-left: 1em;
}
接著在 PageTitle 元件加入 pageTitle
輸入屬性,並利用 <h2>
標籤顯示在頁面上。
@Component({
selector: "app-page-title",
templateUrl: "./page-title.component.html",
styleUrls: ["./page-title.component.css"],
})
export class PageTitleComponent {
@Input() pageTitle: string;
}
<h2>{{ pageTitle }}</h2>
<ng-content>
元素來由外部指定需顯示內容在 Angular 應用程式中,除了可以透過 @Input()
裝飾器可以把資料傳入元件,還可以如活字排版一般,利用 <ng-content>
元素在元件中預留空間,在使用該元件的時候才會傳入此空間的 HTML 內容。因此,直接在 page-container.component.html 檔案使用 <ng-content>
元素。
<ng-content></ng-content>
然後在 app.component.html 中就可使用 PageContainer 元件,並將原內容程式放在此標籤內。
<app-page-container>
<div>
<span>
<button type="button" (click)="onLoad()">載入資料</button>
<button type="button" (click)="onClear()">清空資料</button>
</span>
<span>實際完成率:{{ completeRate | percent: '1.0-2' }}</span>
</div>
<app-task-list [tasks]="tasks"></app-task-list>
<pre>{{ tasks | json }}</pre>
</app-page-container>
<ng-content>
元素 select 屬性設定標題在 Angular 應用程式中,透過選擇器指定方式,可用來決定元件 (Component) 與指令 (Direcitve) 的使用方式;也可以在元件內預留多個空間的需求時,利用 <ng-content>
元素的 select 屬性來指定所需套用的選擇器對象。
對象 | 定義方式 | 範例 |
---|---|---|
標籤 (tag) | 標籤名 | h2 |
樣式類別 | .類別名稱 | .title-text |
屬性 (attribute) | [屬性名稱] | [title-text] |
接下來,在 app.component.html 使用 <app-page-title>
標籤,並指定所需要的標題內容。
<app-page-container>
<app-page-title pageTitle="待辦事項清單"></app-page-title>
<div>
<span>
<button type="button" (click)="onLoad()">載入資料</button>
<button type="button" (click)="onClear()">清空資料</button>
</span>
<span>實際完成率:{{ completeRate | percent: '1.0-2' }}</span>
</div>
<app-task-list [tasks]="tasks"></app-task-list>
<pre>{{ tasks | json }}</pre>
</app-page-container>
最後,在 page-container.component.html 設定 <ng-content>
元素的 select 屬性值為 app-page-title 即可。
<div class="page-title">
<ng-content select="app-page-title"></ng-content>
</div>
<ng-content></ng-content>
當元件利用 <ng-content>
元素接收外部指定的 HTML 內容時,可以透過 @ContentChild
裝飾器的屬性來查詢到傳入的子元件。在 Angular 將外部內容投影至元件內時,會呼叫 ngAfterContentInit()
與 ngAfterContentChecked()
兩個鉤子方法 (hook method)。前者會在 onDoCheck()
事件後觸發,且在整個生命週期 (Lifecycle) 只會呼叫一次,在此方法中會初始化 @ContentChild
屬性。後者則是在 ngAfterContentInit()
執行完觸發,並且也會在每次的 ngDoCheck()
之後執行。
@Component({
selector: "app-page-container",
templateUrl: "./page-container.component.html",
styleUrls: ["./page-container.component.css"],
})
export class PageContainerComponent
implements OnInit, DoCheck, AfterContentInit, AfterContentChecked {
@ContentChild(PageTitleComponent) title: HTMLElement;
constructor() {}
ngOnInit(): void {
console.log("PageContainerComponent - ngOnInit");
}
ngDoCheck(): void {
console.log("PageContainerComponent - ngDoCheck");
}
ngAfterContentInit(): void {
console.log("PageContainerComponent - ngAfterContentInit", this.title);
}
ngAfterContentChecked(): void {
console.log("PageContainerComponent - ngAfterContentChecked");
}
}
在 page-container.component.ts 中加入 @ContentChild
屬性,以取得 AppComponent 所傳入的 PageTitle 元件,並實作各事件介面,以透過 Chorme DevTools 中可以觀察此 ngAfterContentInit()
與 ngAfterContentChecked()
方法的觸發時間點。
@ContentChild
裝飾器會取得單個子元件實體;若需要取得多個子元件時則使用@ContentChildren
,其型別會是QueryList
的泛型型別。
這一篇利用 <ng-content>
元素來實作了將 HTML 內容傳入元件內,並說明了 AfterContentInit
與 AfterContentChecked
兩個生命週期鉤子 (Lifecycle hook method),實作程式碼放在 Github。下一篇將會說明剩下的兩個生命週期鉤子 (Lifecycle hook method) - AfterViewInit
與 AfterViewChecked
。